package com.cpumonitor;

import java.io.BufferedReader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

/**
 * Created with IntelliJ IDEA.
 * ClassName: CpuMonitor
 * Description: TODO
 * User: kevin
 * Date: 2018-11-21
 * Time: 下午5:58
 */
public class CpuMonitor implements CpuMonitorInterface {
    private static final int PRECENT=100;

    /**
     * @Descriptions:获取ｃｐｕ总的数据，包含每个进程信息以及ｃｐｕ总使用率
     * @param
     * @return: com.cpumonitor.CpuTotalWinInfo
     * @Author: kevin
     * @date: 18-11-21 下午11:40
     *
     */
    public CpuTotalInfo getCpuInfors(){

        //进程信息对象初始化
        List<ProcessWinInfor> pre_processWinInfors = null;
        List<ProcessWinInfor> last_processWinInfors = null;
        CpuTotalWinInfo pre_cpuTotalWinInfo = null;
        CpuTotalWinInfo last_cpuTotalWinInfo = null;
        CpuTotalLinuxInfo cpuTotalLinuxInfo = null;

        if(!Utils.isLinux()){
            //记录两次cpu数据
            pre_processWinInfors = getWinprocessInfo();
            last_processWinInfors = getWinprocessInfo();
            // System.out.println(pre_processWinInfors.size()+" "+last_processWinInfors.size());

            //为后面cpu数据计算做准备，
            pre_cpuTotalWinInfo =  getCpuTotalInfo(pre_processWinInfors);
            last_cpuTotalWinInfo = getCpuTotalInfo(last_processWinInfors);
            countprocessInfo(pre_cpuTotalWinInfo, last_cpuTotalWinInfo);
            return last_cpuTotalWinInfo;
        }else {
            cpuTotalLinuxInfo = readCpuTotalInfo();
            return  cpuTotalLinuxInfo;
        }

        //将数据记录在第二次的对象，作为返回
        //return null;
    }

    /**
     * @Descriptions:for linux
     * 读取每个进程ｃｐｕ的使用率，以及总ｃｐｕ使用率，及其他信息,加入集合做返回
     * @param
     * @return: com.cpumonitor.CpuTotalLinuxInfo
     * @Author: kevin
     * @date: 18-11-23 下午9:17
     */

    private CpuTotalLinuxInfo readCpuTotalInfo(){

        CpuTotalLinuxInfo cpuTotalLinuxInfo = new CpuTotalLinuxInfo();
        List<ProcessLinuxInfo> processLinuxInfos = new ArrayList<ProcessLinuxInfo>();
        String cmd = "top -b -n 1";
        String[] procCmd = Utils.getLinuxCommands(cmd);

        BufferedReader input = null;
       // StringBuffer sb = new StringBuffer();
        String line=null;

        try {

            input = Utils.getLinuxCommandResult(procCmd);
            while((line = input.readLine())!=null){
                //System.out.println(line);
                //sb.append(line+System.lineSeparator());
                //处理ｃｐｕ总数据
                if(line.startsWith("%Cpu")){
                    //System.out.println(line);
                    String keys_str[] = line.trim().split("[a-zA-Z,:()\\s]+");
                    //System.out.println(keys_str[i].trim().split("\\s")[1]+":"+keys_str[i].trim().split("\\s")[0]);
                    if(9 == keys_str.length){
                        //取出ｃｐｕ数据
                        double us = Double.valueOf(keys_str[1]).doubleValue();
                        double sy = Double.valueOf(keys_str[2]).doubleValue();
                        double ni = Double.valueOf(keys_str[3]).doubleValue();
                        double id = Double.valueOf(keys_str[4]).doubleValue();
                        double wa = Double.valueOf(keys_str[5]).doubleValue();
                        double hi = Double.valueOf(keys_str[6]).doubleValue();
                        double si = Double.valueOf(keys_str[7]).doubleValue();
                        double st = Double.valueOf(keys_str[8]).doubleValue();
                        //记录总的ｃｐｕ数据
                        cpuTotalLinuxInfo.setUs(us);
                        cpuTotalLinuxInfo.setSy(sy);
                        cpuTotalLinuxInfo.setNi(ni);
                        cpuTotalLinuxInfo.setId(id);
                        cpuTotalLinuxInfo.setWa(wa);
                        cpuTotalLinuxInfo.setHi(hi);
                        cpuTotalLinuxInfo.setSi(si);
                        cpuTotalLinuxInfo.setSt(st);
                    }

                }
                //跳过标题行
                if(line.startsWith("  PID"))continue;
                //处理进程数据
                if(line.startsWith(" ")){
                    String values_str[] = line.trim().split("\\s+");
                    if(12 == values_str.length){
                       /* for(int i=0;i<values_str.length;i++){
                            System.out.print(values_str[i]+" ");
                        }
                        System.out.println();*/
                        //获取ｃｐｕ信息
                        long pid = Long.valueOf(values_str[0]).longValue();
                        String user = values_str[1];
                        String pr = values_str[2];
                        long ni = Long.valueOf(values_str[3]).longValue();
                        long virt = Long.valueOf(values_str[4]).longValue();
                        String res = values_str[5];
                        String shr = values_str[6];
                        char s = values_str[7].charAt(0);
                        double cpu = Double.valueOf(values_str[8]).doubleValue();
                        double mem = Double.valueOf(values_str[9]).doubleValue();
                        String time = values_str[10];
                        String command = values_str[11];

                        ProcessLinuxInfo processLinuxInfo = new ProcessLinuxInfo();

                        //设置ｃｐｕ信息
                        processLinuxInfo.setPid(pid);
                        processLinuxInfo.setUser(user);
                        processLinuxInfo.setPriority(pr);
                        processLinuxInfo.setNice(ni);
                        processLinuxInfo.setVirt(virt);
                        processLinuxInfo.setRes(res);
                        processLinuxInfo.setShr(shr);
                        processLinuxInfo.setS(s);
                        processLinuxInfo.setCpu(cpu);
                        processLinuxInfo.setMem(mem);
                        processLinuxInfo.setTime(time);
                        processLinuxInfo.setCommand(command);

                        //将次进程加入集合
                        processLinuxInfos.add(processLinuxInfo);
                    }
                }
            }

        } catch (IOException e) {
            e.printStackTrace();
        }
        //记录cpu逻辑核数
        int processor_count = Utils.getLinuxProcessorCount();
        cpuTotalLinuxInfo.setCpu_processor(processor_count);
        //将每个进程信息集合加入总ｃｐｕ信息
        cpuTotalLinuxInfo.setProcessLinuxInfos(processLinuxInfos);
        return cpuTotalLinuxInfo;
    }

    /**
     * @Descriptions:
     * ｆｏｒ windows
     * 获取每个进程的信息，加入集合
     * @param
     * @return: java.util.List<com.cpumonitor.ProcessWinInfor>
     * @Author:kevin
     * @date: 18-11-21 下午11:38
     */
    private List<ProcessWinInfor> getWinprocessInfo() {
        String line = null;
        BufferedReader br = null;
        List<ProcessWinInfor> processLinuxInfos = new ArrayList<ProcessWinInfor>();
        //初始化命令参数
        String procCmd = System.getenv("windir")
                + "//system32//wbem//wmic.exe process get Caption,Handle,CommandLine,KernelModeTime,ReadOperationCount,ThreadCount,UserModeTime,WriteOperationCount";

        //出现顺序Caption,Handle,CommandLine,Handle,KernelModeTime,ReadOperationCount,ThreadCount,UserModeTime,WriteOperationCount
        try {
            br = Utils.getWinCommandResult(procCmd);
            line = br.readLine();
            int cap_index = line.indexOf("Caption");
            int cmd_index = line.indexOf("CommandLine");
            int hdl_index = line.indexOf("Handle");
            int kmt_index = line.indexOf("KernelModeTime");
            int roc_index = line.indexOf("ReadOperationCount");
            int thc_index = line.indexOf("ThreadCount");
            int umt_index = line.indexOf("UserModeTime");
            int woc_index = line.indexOf("WriteOperationCount");

            while (null != (line = br.readLine())) {

                if(line.length()>0){
                    // System.out.println(line);
                    //获取相关字段
                    String caption = Utils.substring(line,cap_index,cmd_index-1).trim();
                    String commandLine = Utils.substring(line,cmd_index,hdl_index-1).trim();
                    String handle = Utils.substring(line,hdl_index,kmt_index-1).trim();
                    String kernelModeTime = Utils.substring(line,kmt_index,roc_index-1).trim();
                    String readOperationCount = Utils.substring(line,roc_index,thc_index-1).trim();
                    String threadCount = Utils.substring(line,thc_index,umt_index-1).trim();
                    String userModeTime = Utils.substring(line,umt_index,woc_index-1).trim();
                    String writeOperationCount = Utils.substring(line,woc_index,line.length()-1).trim();

                    ProcessWinInfor processWinInfor = new ProcessWinInfor();

                    //设置进程信息，Caption,Handle,CommandLine,KernelModeTime,ReadOperationCount,ThreadCount,UserModeTime,WriteOperationCount
                    if(null != caption ) processWinInfor.setCaption(caption);
                    if(null != commandLine ) processWinInfor.setCommandLine(commandLine);
                    if(null != handle && !handle.equals("")) processWinInfor.setHandle(Long.valueOf(handle).longValue());
                    if(null != kernelModeTime && !kernelModeTime.equals("")) processWinInfor.setKernelModeTime(Long.valueOf(kernelModeTime).longValue());
                    if(null != readOperationCount && !readOperationCount.equals("")) processWinInfor.setReadOperationCount(Long.valueOf(readOperationCount).longValue());
                    if(null != threadCount && !threadCount.equals("")) processWinInfor.setThreadCount(Long.valueOf(threadCount).longValue());
                    if(null != userModeTime && !userModeTime.equals("")) processWinInfor.setUserModeTime(Long.valueOf(userModeTime).longValue());
                    if(null != writeOperationCount && !writeOperationCount.equals("")) processWinInfor.setWriteOperationCount(Long.valueOf(writeOperationCount).longValue());

                    processLinuxInfos.add(processWinInfor);
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        }

        return processLinuxInfos;
    }

    /**
     * @Descriptions:
     * ｆｏｒ windows:
     * 通过每个进程信息计算总的ｃｐｕ信息，并将所有进程（ｌｉｓｔ）加入此次扫描到的ｃｐｕ总信息（对象）
     * @param processWinInfors
     * @return: com.cpumonitor.CpuTotalWinInfo
     * @Author: kevin
     * @date: 18-11-21 下午11:42
     */
    private CpuTotalWinInfo getCpuTotalInfo(List<ProcessWinInfor> processWinInfors) {

        long idleTime = 0;
        long kernelTime = 0;
        long userTime = 0;
        CpuTotalWinInfo cpuTotalWinInfo = new CpuTotalWinInfo();

        for(int i = 0; i< processWinInfors.size(); i++){

            //获取进程名，cpu内核时间，用户cpu时间
            String caption = processWinInfors.get(i).getCaption();
            long kernelModeTime = processWinInfors.get(i).getKernelModeTime();
            long userModeTime = processWinInfors.get(i).getUserModeTime();

            //cpu空闲时间记录
            /*if (caption.equals("System Idle Process") || caption.equals("System")) {
                idleTime += kernelModeTime;
                idleTime += userModeTime;
                continue;
            }*/
            if (caption.equals("System Idle Process")) {
                idleTime += kernelModeTime;
                idleTime += userModeTime;
                continue;
            }
            //cpu使用时间记录
            kernelTime += kernelModeTime;
            userTime += userModeTime;
        }

        cpuTotalWinInfo.setIdleTime(idleTime);
        cpuTotalWinInfo.setKernelTime(kernelTime);
        cpuTotalWinInfo.setUserTime(userTime);
        cpuTotalWinInfo.setProcessWinInforList(processWinInfors);

        return cpuTotalWinInfo;
    }

    /**
     * @Descriptions:
     * ｆｏｒ windows
     * 通过两次扫描记录的ｃｐｕ的信息，来计算ｃｐｕ总的使用率和每个进程的使用率
     * @param pre_cpuTotalWinInfo
    * @param last_cpuTotalWinInfo
     * @return: java.util.List<com.cpumonitor.ProcessWinInfor>
     * @Author: kevin
     * @date: 18-11-21 下午11:43
     */
    private List<ProcessWinInfor> countprocessInfo(CpuTotalWinInfo pre_cpuTotalWinInfo, CpuTotalWinInfo last_cpuTotalWinInfo){

        //第一次瞬时cpu空闲，cpu使用时间，用户态时间
        long pre_cpu_total_idle = pre_cpuTotalWinInfo.getIdleTime();
        long pre_cpu_total_kernel = pre_cpuTotalWinInfo.getKernelTime();
        long pre_cpu_total_user = pre_cpuTotalWinInfo.getUserTime();
        //第二次瞬时cpu空闲，cpu使用时间，用户态时间
        long last_cpu_total_idle = last_cpuTotalWinInfo.getIdleTime();
        long last_cpu_total_kernel = last_cpuTotalWinInfo.getKernelTime();
        long last_cpu_total_user = last_cpuTotalWinInfo.getUserTime();

        //第一次和第二次的cpu空闲时间和cpu使用时间,用户态时间做差
        long now_cpu_total_idle = last_cpu_total_idle - pre_cpu_total_idle;
        long now_cpu_toatl_kernel = last_cpu_total_kernel - pre_cpu_total_kernel;
        long now_cpu_total_user = last_cpu_total_user - pre_cpu_total_user;

        List<ProcessWinInfor> pre_processWinInfors = pre_cpuTotalWinInfo.getProcessWinInforList();
        List<ProcessWinInfor> last_processWinInfors = last_cpuTotalWinInfo.getProcessWinInforList();
        int pro_size = pre_processWinInfors.size() < last_processWinInfors.size() ? pre_processWinInfors.size() : last_processWinInfors.size();
       // System.out.println(now_cpu_toatl_kernel+" "+now_cpu_total_idle);
        //计算cpu总使用率
        double now_cpu_total_use = PRECENT * (now_cpu_toatl_kernel+now_cpu_total_user) * 1.0 / (now_cpu_toatl_kernel + now_cpu_total_user + now_cpu_total_idle);
        last_cpuTotalWinInfo.setCpuUsage(now_cpu_total_use);

        //循环计算每个进程的cpu使用率
        for(int i=0;i<pro_size;i++){

            if(!pre_processWinInfors.get(i).getCaption().equals(last_processWinInfors.get(i).getCaption()))continue;
            long pre_pro_kernel = pre_processWinInfors.get(i).getKernelModeTime();
            long pre_pro_user = pre_processWinInfors.get(i).getUserModeTime();
            long last_pro_kernel = last_processWinInfors.get(i).getKernelModeTime();
            long last_pro_user = last_processWinInfors.get(i).getUserModeTime();
            //两次cpu时间差
            long devi_pro_kernel=( last_pro_kernel - pre_pro_kernel ) > 0 ? last_pro_kernel - pre_pro_kernel : 0;
            long devi_pro_user = ( last_pro_user - pre_pro_user ) > 0 ? last_pro_user - pre_pro_user : 0;
            //计算单个进程cpu使用率
            double process_use = PRECENT * (devi_pro_kernel + devi_pro_user) * 1.0 / ( now_cpu_toatl_kernel + now_cpu_total_idle );
            //System.out.println(last_cpuTotalWinInfo.getprocessWinInforList().get(i).getCaption()+": "+process_use);
            last_cpuTotalWinInfo.getProcessWinInforList().get(i).setCpuUsage(process_use);
        }
        //将数据记录在第二次的对象，作为返回
        return last_processWinInfors;
    }
}
